ASSUME CS:CODE,DS:DATA

DATA	SEGMENT
	old_int dw 4 dup(0);保存旧int9,int1ch中断
	key db ?;最后按下的控制键（wasd）
	esc_trigger db 0;esc键被触发（释放）
	count_max db 5
	count db 1;定时器中断计数器
DATA	ENDS

DISPLAY_BUFFER equ 0b800h;显示缓冲区地址
PORT_KEY_DAT EQU 60h		;键盘数据接口
PORT_KEY_STA EQU 64h		;键盘控制接口

;在l行c列处显示t，均应为立即数，字符位于es:[行数*160][列数*2]
;t低字节位ascii，高字节为格式https://img-blog.csdnimg.cn/20200116141256815.png
SHOW macro l,c,t
	mov ax,160
	mov bx,l
	mul bx
	mov bx,ax
	mov ax,2
	mov si,c
	mul si
	mov si,ax
	mov ax,t
	mov es:[bx][si],ax
endm

CODE	SEGMENT
start:
	mov ax,data
	mov ds,ax
	call save_int
	call set_new_int
	mov ax,DISPLAY_BUFFER
	mov es,ax
main_loop:;主循环，处理需要立即响应的时间
	cmp esc_trigger,1
	jz exit
	jmp main_loop
exit:
	call restore_int
	mov ah,4ch
	int 21h

save_int:
	mov ax,0
	mov es,ax
	cli
	push word ptr es:[9*4]
	pop word ptr [old_int]
	push word ptr es:[9*4+2]
	pop word ptr [old_int+2]
	push word ptr es:[1ch*4]
	pop word ptr [old_int+4]
	push word ptr es:[1ch*4+2]
	pop word ptr [old_int+6]
	sti
	ret

;自定义按键中断处理程序
new_int9:
	push ax
	mov al,0adh
	out PORT_KEY_STA,al
	in al,PORT_KEY_DAT
	cmp al,81h;<esc>键释放
	jnz int9_key_w
	mov esc_trigger,1
	jmp int9_ret
int9_key_w:
	cmp al,11h;w键按下
	jnz int9_key_a
	mov key,'w'
	jmp int9_ret
int9_key_a:
	cmp al,1eh
	jnz int9_key_s
	mov key,'a'
	jmp int9_ret
int9_key_s:
	cmp al,1fh
	jnz int9_key_d
	mov key,'s'
	jmp int9_ret
int9_key_d:
	cmp al,20h
	jnz int9_ret
	mov key,'d'
int9_ret:
	mov al,0aeh
	out PORT_KEY_STA,al
	mov al,20h
	out 20h,al
	pop ax
	iret

;自定义定时器中断处理程序，每55ms触发一次
new_int1ch:
	push ax
	dec count
	jz step
	jmp return
step:;时间步，处理间隔固定时间发生的事件
	mov al,count_max
	mov count,al
	SHOW 2,3,0020h
	SHOW 3,2,0020h
	SHOW 3,3,0020h
	SHOW 3,4,0020h
	mov al,key
key_w:
	cmp al,'w'
	jnz key_a
	SHOW 2,3,7157h
	jmp clear_key
key_a:
	cmp al,'a'
	jnz key_s
	SHOW 3,2,7141h
	jmp clear_key
key_s:
	cmp al,'s'
	jnz key_d
	SHOW 3,3,7153h
	jmp clear_key
key_d:
	cmp al,'d'
	jnz return
	SHOW 3,4,7144h
	jmp clear_key
clear_key:
	mov key,0
return:
	mov al,20h
	out 20h,al
	pop ax
	iret

set_new_int:
	mov ax,0
	mov es,ax
	cli
	mov word ptr es:[9*4],offset new_int9
	mov es:[9*4+2],cs
	mov word ptr es:[1ch*4],offset new_int1ch
	mov es:[1ch*4+2],cs
	sti
	ret
	
restore_int:
	mov ax,0
	mov es,ax
	cli
	push word ptr [old_int]
	pop word ptr es:[9*4]
	push word ptr [old_int+2]
	pop word ptr es:[9*4+2]
	push word ptr [old_int+4]
	pop word ptr es:[1ch*4]
	push word ptr [old_int+6]
	pop word ptr es:[1ch*4+2]
	sti
	ret

CODE	ENDS
END		START